package com.fanghuaiming.seata.item.tcc.impl;

import com.fanghuaiming.seata.item.dao.mapper.SeataTccSkuMapper;
import com.fanghuaiming.seata.item.dao.model.SeataTccSku;
import com.fanghuaiming.seata.item.tcc.SeataPhaseTccItem;
import com.fanghuaiming.seata.item.tcc.idempotent.SeataTccItemResultHolder;
import io.seata.rm.tcc.api.BusinessActionContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

/****
 * @description: 订单tcc接口实现类
 * @version:1.0.0
 * @author fanghuaiming
 * @data Created in 2020/11/30 下午4:59
 *
 */
@Component
@Slf4j
public class SeataPhaseTccItemImpl implements SeataPhaseTccItem {

    /**
     * mapper
     */
    @Autowired
    private SeataTccSkuMapper seataTccSkuMapper;

    /**
     * @Description: 第一阶段
     *
     * @param:
     * @return:
     * @auther: fanghuaiming
     * @date: 2020/11/30 下午5:02
     * @version:1.0.0
     */
    @SuppressWarnings("all")
    @Transactional
    @Override
    public Boolean prepareDecreaseItem(BusinessActionContext businessActionContext,
            Long productId,
            Integer count) {
        //添加标记
        SeataTccItemResultHolder.setResult(getClass(),businessActionContext.getXid(),"p");
        log.info("==========减少库存第一阶段 开始执行冻结操作,事务组Xid:{}==========",businessActionContext.getXid());
        //先查询库存 看是否可以冻结
        SeataTccSku seataTccSku = seataTccSkuMapper.selectById(productId);
        if (seataTccSku.getResidue()<count){
            throw new  RuntimeException("==========库存量不足，无法完成冻结操作==========");
        }
        //冻结操作
        seataTccSkuMapper.updateFrozen(seataTccSku.getProductId(),
                seataTccSku.getResidue() - count,seataTccSku.getFrozen() + count);

        log.info("==========减少库存第一阶段 执行冻结操作成功==========");

        return true;
    }

    /**
     * @Description: 第二阶段
     *
     * @param:
     * @return:
     * @auther: fanghuaiming
     * @date: 2020/11/30 下午5:03
     * @version:1.0.0
     */
    @SuppressWarnings("all")
    @Transactional
    @Override
    public boolean commit(BusinessActionContext businessActionContext) {
        log.info("========== 即将开始Confirm--> 减少库存第二阶段 开始执行提交操作,事务组Xid:{}==========",businessActionContext.getXid());
        //幂等
        if (SeataTccItemResultHolder.getResult(getClass(),businessActionContext.getXid())==null){
            log.info("商品库存Confirm已经确认过");
            return  true;
        }

        long productId = Long.parseLong(businessActionContext.getActionContext("productId").toString());
        int count = Integer.parseInt(businessActionContext.getActionContext("count").toString());

        seataTccSkuMapper.updateFrozenToUsed(productId,count);
        log.info("========== 已经完成Confirm--> 减少库存第二阶段 执行提交操作完毕==========");

        //删除标识
        SeataTccItemResultHolder.removeResult(getClass(), businessActionContext.getXid());
        return true;
    }

    /**
     * @Description: 第二阶段
     *
     * @param:
     * @return:
     * @auther: fanghuaiming
     * @date: 2020/11/30 下午5:03
     * @version:1.0.0
     */
    @SuppressWarnings("all")
    @Transactional
    @Override
    public boolean rollback(BusinessActionContext businessActionContext) {
        log.info("========== 即将开始Cancle--> 减少库存第二阶段 执行回滚操作,事务组Xid:{}==========",businessActionContext.getXid());
        //防止重复的回滚
        if (SeataTccItemResultHolder.getResult(this.getClass(),businessActionContext.getXid()) == null){
            log.info("商品库存Cancle已经取消过");
            return true;
        }
        long productId = Long.parseLong(businessActionContext.getActionContext("productId").toString());
        int count = Integer.parseInt(businessActionContext.getActionContext("count").toString());
        seataTccSkuMapper.updateFrozenToResidue(productId,count);
        log.info("========== 已经完成Cancle--> 减少库存第二阶段 执行回滚操作,事务组Xid:{}==========",businessActionContext.getXid());
        //删除标识
        SeataTccItemResultHolder.removeResult(this.getClass(), businessActionContext.getXid());
        return true;
    }
}
